package com.zsqat.eshop.product.exception;

import com.zsqat.common.enums.BizCodeEnum;
import com.zsqat.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
// 此注解作用：集中处理所有异常
@RestControllerAdvice(basePackages="com.zsqat.eshop.product.controller")
public class ProductExceptionAdvice {
  // 此注解作用：告诉springmvc 这个集中处理异常类在此方法中都可以处理哪种类型的异常，在此我们处理数据校验类异常
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST) // 如果添加此句话，前台页面收不到错误提示信息，但是前台页面控制台有400错误提示
  public R handleValidException(MethodArgumentNotValidException e) {
    log.error("数据效验出现问题{},异常类型{}", e.getMessage(), e.getClass());
    BindingResult results = e.getBindingResult();

    /*Map<String, String> mapErr = new HashMap<>();
    results.getFieldErrors().forEach((x) -> {
      mapErr.put(x.getField(), x.getDefaultMessage());
    });*/
    Map<String, String> mapErr = results.getFieldErrors()
        .stream()
        .collect(Collectors.toMap(x->x.getField(), x->x.getDefaultMessage()));
    return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMessage())
        .put("data", mapErr);
  }

  // 默认异常处理
  @ExceptionHandler(value = Throwable.class)
  public R handleException(Throwable e) {

    log.error("错误异常{}", e);
    return R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(), BizCodeEnum.UNKNOWN_EXCEPTION.getMessage());
  }
}

/*
  @RestControllerAdvice
  定义：是组件注解，它使得其实现类能够被classpath扫描自动发现
       如果应用是通过 mvc 命名空间或 mvc Java编程方式配置，那么该特性默认是自动开启的。
       @RestControllerAdvice相当于Controller的切面，对异常统一处理，定制，这样更好返回给前端。

  作用：主要配合@ExceptionHandler使用，统一处理异常情况。

  @ExceptionHandler：统一处理某一类异常，从而能够减少代码重复率和复杂度
  @ControllerAdvice：异常集中处理，更好的使业务逻辑与异常处理剥离开；其是对Controller层进行拦截


  @ResponseStatus：可以将某种异常映射为HTTP状态码
    如果添加此句话，前台页面收不到错误提示信息，但是前台页面控制台有4xx错误提示
*/
